#include <iostream>
#include <queue>
#include <pthread.h>

namespace BlockQueueModule
{


	static const int Size = 10;
	template <typename T>
	class BlockQueue
	{
	private:
		bool ISFull() { return _q.size() == _cap; }
		bool ISEmpty() { return _q.empty(); }

	public:
		// 构造列表 ：， ，
		BlockQueue(int cap = Size) : _cap(cap), _cwait_num(0), _pwait_num(0)
		{
			pthread_mutex_init(&_mutex, nullptr);
			pthread_cond_init(&_production_cond, nullptr);
			pthread_cond_init(&_consume_cond, nullptr);
		}
		void Equeue(const T &in)
		{
			pthread_mutex_lock(&_mutex);
			// 你想放数据，就能放数据吗？？生产数据是有条件的！
			// 如果满了就不放
			while (ISFull())
			{
				std::cout << "生产者进入等待..." << std::endl;
				_pwait_num++;
				pthread_cond_wait(&_production_cond, &_mutex);
				_pwait_num--;
				std::cout << "生产者被唤醒" << std::endl;
			}
			// if(IsFull())不满足 || 线程被唤醒
			_q.push(in); // 生产
			// 肯定有数据,如果消费者队列有则唤醒
			if (_cwait_num)
			{
				// 叫醒消费者
				std::cout << "叫醒消费者..." << std::endl;
				pthread_cond_signal(&_consume_cond);
			}
			pthread_mutex_unlock(&_mutex);
		}
		void Pop(T *out)
		{
			pthread_mutex_lock(&_mutex);
			// 你想放数据，就能放数据吗？？生产数据是有条件的！
			while (ISEmpty())
			{
				std::cout << "消费者进入等待..." << std::endl;
				_cwait_num++;
				pthread_cond_wait(&_consume_cond, &_mutex);
				_cwait_num--;
				std::cout << "消费者被唤醒" << std::endl;
			}
			// 4. if(IsEmpty())不满足 || 线程被唤醒
			*out = _q.front();
			_q.pop();
			// 肯定有空余，如果生产者队列有则唤醒
			if (_pwait_num)
			{
				std::cout << "叫醒生产者..." << std::endl;
				pthread_cond_signal(&_production_cond);
			}
			pthread_mutex_unlock(&_mutex);
		}
		~BlockQueue()
		{
			pthread_mutex_destroy(&_mutex);
			pthread_cond_destroy(&_production_cond);
			pthread_cond_destroy(&_consume_cond);
		}

	private:
		std::queue<T> _q;
		int _cap;
		pthread_mutex_t _mutex;
		pthread_cond_t _production_cond;
		pthread_cond_t _consume_cond;
		int _cwait_num;
		int _pwait_num;
	};
}